import React, {
    PropsWithChildren,
    CSSProperties,
    ReactNode,
    useMemo,
    useState,
    useRef,
    useEffect,
  } from "react";
  import {createPortal} from "react-dom";
  import Button from "../button";
  import { Icon } from "../icon";
  import styled, { css, keyframes } from "styled-components";
  import { color, typography } from "../shared/styles";
  import { darken, rgba, opacify } from "polished";
  import { easing } from "../shared/animation";
  
  export const modalOpenAnimate = keyframes`
    0% {
      opacity: 0;
      transform: scaleY(0,0);
    }
    100% {
      opacity: 0;
      transform: scale(1,1);
      transform-origin: center;
    }
  `;
  
  export const modalCloseAnimate = keyframes`
    0% {
      opacity: 0;
      transform: scale(1,1);
      transform-origin: center;
    }
    100% {
      opacity: 0;
      transform: scaleY(0,0);
    }
  `;
  
  const ModalWrapper = styled.div`
    position: fixed;
    top: 0;
    left: 0;
    right: 0;
    bottom: 0;
    z-index: 1000;
  `;
  
  const ModalViewPort = styled.div<{ visible: boolean; delay: number }>`
    background: #fff;
    border: none;
    border-radius: 5px;
    box-shadow: 2px 2px 4px #d9d9d9;
    text-shadow: 1px 1px 4px #d9d9d9, -1px -1px 4px #fff;
    margin: 0 auto;
    min-width: 320px;
    overflow: hidden;
    padding: 8px;
    position: relative;
    top: 100px;
    transition: all 0.5s cubic-bezier(0.23, 1, 0.32, 1);
    width: 30%;
    z-index: 1001;
    ${(props) =>
      props.visible &&
      css`
        animation: ${modalOpenAnimate} ${props.delay / 1000}s ease-in;
      `}
    ${(props) =>
      !props.visible &&
      css`
        animation: ${modalCloseAnimate} ${props.delay / 1000}s ease-in;
      `}
  `;
  
  const ModalMask = styled.div`
    background-color: rgba(0, 0, 0, 0.45);
    bottom: 0;
    left: 0;
    position: fixed;
    right: 0;
    top: 0;
  `;
  
  const CloseBtn = styled.div`
    position: absolute;
    right: 5px;
    top: 5px;
  `;
  
  const ConfirmWrapper = styled.div`
    display: flex;
    justify-content: flex-end;
    align-item: center;
    padding: 10px;
  `;
  
  const ChildrenWrapper = styled.div`
    min-height: 100px;
    padding: 10px;
  `;
  
  const TitleWrapper = styled.div`
    height: 30px;
    line-height: 30px;
    font-size: ${typography.size.m2}px;
    font-weight: ${typography.weight.bold};
    padding: 5px;
  `;
  
  export type ModalProps = {
    /** 父组件用来控制的状态 */
    visible: boolean;
    /** 容器位置 */
    container?: Element;
    /** 父组件setstate */
    parentSetState: (v: boolean) => void;
    /** 弹出框标题 */
    title?: ReactNode;
    /** 是否有确认按钮 */
    confirm?: boolean;
    /** 改变确认按钮文本*/
    okText?: string;
    /** 改变取消按钮文本*/
    cancelText?: string;
    /** 点了确认的回调，如果传了，需要自行处理关闭 */
    onOk?: (set:(v: boolean) => void) => void;
    /** 点了取消的回调，如果传了，需要自行处理关闭*/
    onCancel?: (set:(v: boolean) => void) => void;
    /** 点确认或者取消都会走的回调 */
    callback?: (v: boolean) => void;
    /** 点击mask是否关闭模态框 */
    maskClose?: boolean;
    /** 是否有mask */
    mask?: boolean;
    /** 自定义模态框位置 */
    style?: CSSProperties;
    /** 是否有右上角关闭按钮 */
    closeButton?: boolean;
    /** 动画时间 */
    delay?: number;
    /** 是否停止滚动*/
    stopScroll?: boolean;
    /** portralstyle*/
    portralStyle?: CSSProperties;
    /** portral的回调 */
    refCallback?: (ref: HTMLDivElement) => void;
    /** 没点确认于取消，直接关闭的回调 */
    closeCallback?: () => void;
  };
  
  export function useStateAnimation(
    parentSetState: (v: boolean) => void,
    delay: number = 300
  ): [boolean, (v: boolean) => void, () => void] {
    const [state, setState] = useState(true);
    const [innerClose, unmount] = useMemo(() => {
      let timer: number;
      let innerclose = (v: boolean) => {
        setState(v);
        timer = window.setTimeout(() => {
          parentSetState(v);
          setState(true);
        }, delay);
      };
      let unmount = () => window.clearTimeout(timer);
      return [innerclose, unmount];
    }, [setState, parentSetState, delay]);
    return [state, innerClose, unmount];
  }
  
  export function useStopScroll(state: boolean, delay: number, open?: boolean) {
    if (open) {
      let width = window.innerWidth - document.body.clientWidth;
      if (state) {
        document.body.style.overflow = "hidden";
        document.body.style.width = `calc(100% - ${width}px)`;
      } else {
        //等动画渲染
        setTimeout(() => {
          document.body.style.overflow = "auto";
          document.body.style.width = `100%`;
        }, delay);
      }
    }
  }
  
  export function Modal(props: PropsWithChildren<ModalProps>) {
    const {
      visible,
      maskClose,
      closeButton,
      delay,
      mask,
      container,
      confirm,
      okText,
      style,
      cancelText,
      onOk,
      onCancel,
      callback,
      title,
      parentSetState,
      stopScroll,
      portralStyle,
      refCallback,
      closeCallback,
    } = props;
    const ref = useRef<HTMLDivElement>(null);
  
    const [state, setState, unmount] = useStateAnimation(parentSetState, delay);
  
    const render = useMemo(() => {
      if (!visible) {
        unmount();
        return null;
      } else {
        return createPortal(
          <ModalWrapper ref={ref} style={portralStyle}>
            <ModalViewPort style={style} visible={state} delay={delay!}>
              <div>
                {title && <TitleWrapper>{title}</TitleWrapper>}
                {closeButton && (
                  <CloseBtn>
                    <Button
                      style={{
                        background: "white",
                        borderRadius: "5px",
                        padding: "5px",
                      }}
                      onClick={() => {
                        setState(false);
                        if (closeCallback) closeCallback();
                      }}
                    >
                      <Icon icon="closeAlt"></Icon>
                    </Button>
                  </CloseBtn>
                )}
              </div>
              {<ChildrenWrapper>{props.children}</ChildrenWrapper>}
              {confirm && (
                <ConfirmWrapper>
                  <Button
                    appearance="secondary"
                    onClick={() => {
                      onOk ? onOk(setState) : setState(false);
                      if (callback) callback(true);
                    }}
                  >
                    {okText ? okText : "确认"}
                  </Button>
                  <Button
                    appearance="secondary"
                    onClick={() => {
                      onCancel ? onCancel(setState) : setState(false);
                      if (callback) callback(false);
                    }}
                    style={{ marginLeft: "10px" }}
                  >
                    {cancelText ? cancelText : "取消"}
                  </Button>
                </ConfirmWrapper>
              )}
            </ModalViewPort>
            {mask && (
              <ModalMask
                onClick={() => {
                  if (maskClose) {
                    setState(false);
                    if (closeCallback) {
                      closeCallback();
                    }
                  }
                }}
              ></ModalMask>
            )}
          </ModalWrapper>,
          container!
        );
      }
    }, [
      callback,
      cancelText,
      closeButton,
      closeCallback,
      confirm,
      container,
      mask,
      maskClose,
      okText,
      onCancel,
      onOk,
      portralStyle,
      props.children,
      setState,
      style,
      title,
      state,
      visible,
      delay,
      unmount,
    ]);
    useStopScroll(visible!, 300, stopScroll!);
    useEffect(() => {
      if (refCallback && ref.current) {
        refCallback(ref.current);
      }
    }, [refCallback]);
    return <>{render}</>;
  }
  
  Modal.defaultProps = {
    visible: false,
    container: window.document.body,
    confirm: true,
    title: "标题",
    maskClose: true,
    mask: true,
    closeButton: true,
    delay: 200,
    stopScroll: true,
    btnSize: "default"
  };